package com.lemon.cloud.gray.rule;

import cn.hutool.core.util.RandomUtil;
import com.lemon.cloud.comm.constants.GrayConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.*;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.http.HttpHeaders;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @author huangds
 * <p>
 * 基于客户端版本号灰度路由
 */
@Slf4j
public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer {

    private final String serviceId;
    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public GrayRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        super(serviceInstanceListSupplierProvider, serviceId);
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    public Mono<Response<ServiceInstance>> choose(Request request) {
        // 提供备选的服务实例列表
        ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        // 选择服务实例
        return supplier.get(request).next().map((serviceInstances) -> this.processInstanceResponse(supplier, serviceInstances, request));
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
                                                              List<ServiceInstance> serviceInstances,
                                                              Request request) {
        // 从备选的服务列表中选择一个具体的服务实例
        Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances, request);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }
        return serviceInstanceResponse;
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances,
                                                          Request request) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.error("No servers available for service: " + this.serviceId);
            }
            return new EmptyResponse();
        } else {
            RequestDataContext requestContext = (RequestDataContext) request.getContext();
            HttpHeaders headers = requestContext.getClientRequest().getHeaders();
            List<String> headersList = headers.get(GrayConstant.GRAY_FLAG);
            if (headersList != null && !headersList.isEmpty() &&
                    headersList.getFirst().equals("true")) { // 灰度请求
                List<ServiceInstance> grayList = instances.stream().
                        filter(i -> i.getMetadata().get(GrayConstant.GRAY_FLAG) != null &&
                                i.getMetadata().get(GrayConstant.GRAY_FLAG).equals("true")).
                        toList();
                if (!grayList.isEmpty()) { // 存在灰度服务节点
                    instances = grayList;
                }
            } else {
                instances = instances.stream().
                        filter(i -> i.getMetadata().get(GrayConstant.GRAY_FLAG) == null ||
                                !i.getMetadata().get(GrayConstant.GRAY_FLAG).equals("true")).
                        toList();
            }
            ServiceInstance instance = RandomUtil.randomEle(instances);
            return new DefaultResponse(instance);
        }
    }
}
